iT邦幫忙

2025 iThome 鐵人賽

DAY 3
0
Software Development

通勤看手機就可讀懂的 Elixir 語言入門教學系列 第 3

過一遍常用的複合型態 - List

  • 分享至 

  • xImage
  •  

串列 (list) (linked list)

重要: 在 Elixir 中的串列為鏈結串列(linked list)

https://ithelp.ithome.com.tw/upload/images/20250916/20141054tkbzRO7zEf.png

如上圖所示,鏈結串列 的結構讓 Elixir 的串列有幾個特點:

  • 增加或是移除第一個項目很快 (O(1))
  • 算長度或是取第幾個的值這種因為結構關係需要從頭到尾讀一遍的行為較慢 (O(n))

這種特性在 functional 程式風格中很方便遞迴使用,
假如今天要處理一個串列可以這樣寫

langs = ["Elixir", "Clojure", "Erlang", "Ocaml", "Rust"]

def admire(items) do
  case items do
    [] ->
      IO.puts "遞迴結束"
    [head | tail] -> 
      IO.puts "#{head} 最棒了"
      admire(tail)
  end
end

admire(langs)

在第一次呼叫時

admire(["Elixir", "Clojure", "Erlang", "Ocaml", "Rust"])

case 裡面進行 pattern matching

case ["Elixir", "Clojure", "Erlang", "Ocaml", "Rust"] do
    [] -> # 第一個匹配嘗試
      IO.puts "遞迴結束"

[]["Elixir", "Clojure", "Erlang", "Ocaml", "Rust"] 匹配失敗

換下一個

case ["Elixir", "Clojure", "Erlang", "Ocaml", "Rust"] do
  [head | tail] -> # 第二個匹配嘗試
    IO.puts "#{head} 最棒了"
    admire(tail)

[head | tail] 這個模式會將 list 的第一個值放到 head,剩下的到 tail
https://ithelp.ithome.com.tw/upload/images/20250916/20141054wekMMStlbc.png

接著使用 tail 當作原本的 langs 放進 admire 再執行一次
直到 tail 變成 [] 遞迴結束

備註 1: def 應要在模組裡面才能被定義,這邊方便說明忽略
備註 2: 這個函式沒有尾遞迴最佳化,後續介紹函式呼叫時一起說明
備註 3: 鏈結串列 wiki

List 常用的函式

除了 List 模組內的函式外
更多更常使用的是在 Enum 模組
另外也有獨立的 hdtl 可以呼叫

hd(langs) #=> "Elixir"
tl(langs) #=> ["Clojure", "Erlang", "Ocaml", "Rust"]
Enum.reverse(langs) #=> ["Rust", "Ocaml", "Erlang", "Clojure", "Elixir"]
Enum.take(langs, 2) #=> ["Elixir", "Clojure"]
List.delete(langs, "Clojure") #=> ["Elixir", "Erlang", "Ocaml", "Rust"]

++ (連接運算子), -- (差集運算子)

Elixir 的 Kernel 模組有提供 ++ (連接運算子), -- (差集運算子) 這兩個額外的函式讓我們可以簡化一些寫法

# 連接兩個串列
[1, 2, 3] ++ [4, 5, 6]
#=> [1, 2, 3, 4, 5, 6]

# 可連接空的串列
[] ++ [1, 2, 3]
#=> [1, 2, 3]

# 差集操作
[1, 2, 3, 4, 5] -- [2, 4]
#=> [1, 3, 5]

# 移除重複元素(只移除第一個匹配)
[1, 2, 2, 3, 2] -- [2]
#=> [1, 2, 3, 2] (只移除第一個 2)

# 移除不存在的元素
[1, 2, 3] -- [4, 5]
#=> [1, 2, 3] (沒有變化,不會報錯)

備註 1: Kernel 模組內的函數為不需要呼叫模組也不需要 import 即可直接使用的 Elixir 核心函數群,
之前使用的 +, -, div, 與這次介紹的 hd, tail 都是 Kernel 模組的成員。

備註 2: 用起來像語法的 def, defmodule, |> 其實也是 Kernel 的函式,偏後面的章節會介紹他們實際上是怎麼組成的。


上一篇
過一遍常用的基本型態
下一篇
複合型態 Map 與 Tuple
系列文
通勤看手機就可讀懂的 Elixir 語言入門教學4
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言